using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Reflection;
using SolarWinds.Helpers;

namespace SolarWinds.Screens
{
    public abstract class Screen : DrawableComponentManager
    {
        #region Public Properties

        /// <summary>
        /// Specifies the name for a screen
        /// </summary>
        private string mName = "";

        public string Name
        {
            get { return mName; }
            set { mName = value; }
        }

        public float Rotation { get; set; }

        /// <summary>
        /// Position of the screen inside the viewport.
        /// </summary>
        private Vector2 mPosition = new Vector2(0, 0);

        public Vector2 Position
        {
            get { return mPosition; }
            set { mPosition = value; }
        }

        /// <summary>
        /// Scaling of the screen relative to the viewport.
        /// </summary>
        private float mScale = 1.0f;

        public float Scale
        {
            get { return mScale; }
            set { mScale = value; }
        }

        private Rectangle mCropRectangle;

        public Rectangle CropRectangle
        {
            get { return mCropRectangle; }
            set { mCropRectangle = value; }
        }

        /// <summary>
        /// The texture on which the screen will be rendered. 
        /// It can be used to draw the screen onto a sprite batch.
        /// </summary>
        private ResolveTexture2D mTexture;

        public Texture2D RenderedTexture
        {
            get { return mTexture; }
        }

        public float ColorReduction { get; set; }
        public bool BlocksUpdate { get; set; }
        public bool BlocksDraw { get; set; }

        private Color mColor = Color.White;

        public Color Color
        {
            get { return mColor; }
            set { mColor = value; }
        }

        private float mAlpha = 1.0f;

        public float Alpha
        {
            get { return mAlpha; }
            set { mAlpha = value; }
        }
        
        #endregion

        IScreenManagerService mScreenService;

        protected IScreenManagerService ScreenManager
        {
            get { return mScreenService; }
        }

        protected Screen(Microsoft.Xna.Framework.Game game)
            :base(game)
        {
        }

        public override void Initialize()
        {
            mScreenService = (IScreenManagerService)
                             Game.Services.GetService(typeof(IScreenManagerService));

            base.Initialize();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (mTexture != null &&
                    !mTexture.IsDisposed)
                {
                    mTexture.Dispose();
                    mTexture = null;
                }
            }

            base.Dispose(disposing);
        }

        protected override void LoadContent()
        {
            base.LoadContent();

            ReloadContent(null, null);
        }

        void ReloadContent(object sender, System.EventArgs e)
        {
            if (mTexture != null &&
                !mTexture.IsDisposed)
            {
                mTexture.ContentLost -= ReloadContent;
                mTexture.Dispose();
                mTexture = null;
            }

            mTexture = new ResolveTexture2D(GraphicsDevice,
                                            GraphicsDevice.Viewport.Width,
                                            GraphicsDevice.Viewport.Height,
                                            1, SurfaceFormat.Color);

            mTexture.ContentLost += ReloadContent;

            mCropRectangle = new Rectangle(0, 0,
                                           GraphicsDevice.Viewport.Width,
                                           GraphicsDevice.Viewport.Height);
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();

            if (mTexture != null &&
                !mTexture.IsDisposed)
            {
                mTexture.Dispose();
                mTexture = null;
            }
        }

        public virtual void RemoveEventHandlers()
        {
            FieldInfo[] fieldInfos = GetType().GetFields(BindingFlags.Default);
            foreach (FieldInfo fieldInfo in fieldInfos)
            {
                EventInfo[] eventInfos = fieldInfo.FieldType.GetEvents();

                foreach (EventInfo eventInfo in eventInfos)
                {
                    eventInfo.GetRaiseMethod();
                }
            }
        }

        public sealed override void Draw(GameTime gameTime)
        {
            GraphicsDevice device = GraphicsDevice;
            device.Clear(Color.TransparentBlack);
            
            // The call to base to  
            base.Draw(gameTime);
            PaintEvent(gameTime);

            device.ResolveBackBuffer(mTexture);
        }

        /// <summary>
        /// The paint event can be overridden in a derived class to paint 
        /// something to the screen without using components.
        /// </summary>
        /// <param name="gameTime"></param>
        protected virtual void PaintEvent(GameTime gameTime) {}

        public int ScreenWidth()
        {
            return GraphicsDevice.Viewport.Width;
        }

        public int ScreenHeight()
        {
            return GraphicsDevice.Viewport.Height;
        }
    }
}